home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
026-050
/
scopedisk47
/
quickcat
/
qcat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-18
|
12KB
|
561 lines
/***********************************************************************
11/88
QCAT v0.01 -- List files on disks or in directories
-----------------
Copyright (C) 1988 by Daniel Elbaum
This software is freely redistributable provided that:
the three files which comprise it (qcat, qcat.c, qcat.doc)
remain intact; all copyright notices contained in any of
the aforementioned files remain intact; and no fee beyond
reasonable remuneration for collation and distribution be
charged for use and/or purveyance.
***********************************************************************/
#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
/* Error descriptor codes */
#define E_NOLOCK (-1)
#define E_NOMEM (-2)
#define E_NOEXAM (-3)
#define E_USAGE (-4)
#define E_OUTPUT (-5)
#define E_LIBRARY (-6)
#define E_NONODE (-100)
#define E_NOSTRING (-101)
/* Manifest constants */
#define NAMSIZ (108)
#define MEMFLOOR (64000L) /* least amt of mem to leave */
#define IREV (1)
#define INAM ("intuition.library")
/* Global data, type and function declarations */
typedef struct IntuitionBase* ib_t;
ib_t IntuitionBase=NULL;
void *OpenLibrary();
FILE *ofp;
struct {
char filenam[NAMSIZ*10];
} fs;
struct namlist {
char *nam;
struct namlist *next;
} nlist;
/*
Acts like a state machine, the state of which
is determined by the combination of arguments
supplied. The while loop sets the state, while
the if switches select action taken according
thereto.
*/
main(c, v)
char **v;
{
register active;
register err;
char *cdrive=NULL;
char *onam=NULL;
char bu[NAMSIZ*10];
char *getcd();
char *realnam();
void getrspinit(), freelist();
++v;
while (**v == '-'){
switch(*++*v){
case 'o': /* specify output file */
if (!*++v) {prerr(NULL, E_USAGE); exit(10);}
else {onam=*v; ++v;}
break;
case 'c': /* continuous listing of 1 drive */
if (!*++v) {prerr(NULL, E_USAGE); exit(10);}
else {cdrive=*v; ++v;}
if (!(IntuitionBase=(ib_t)OpenLibrary(INAM, IREV))){
prerr(NULL, E_LIBRARY); exit(10);
}
break;
default:
prerr(NULL, E_USAGE);
exit(10);
}
}
if (onam){
if (!(ofp=fopen(onam, "w"))){
prerr(onam, E_OUTPUT);
exit(10);
}
}
else ofp=stdout;
if (cdrive){
getrspinit();
if (getresponse()!=FALSE){
for (active=1; active; ){
realnam(cdrive, fs.filenam); /* seed pathname */
if (err=getnams(cdrive)) prerr(cdrive, err);
if (getresponse()==FALSE) active=0;
}
}
}
else if (!*v){
getcd(bu);
strcpy(fs.filenam, bu);
if (err=getnams(bu)) prerr(bu, err);
}
else{
for (; *v; ++v){
realnam(*v, fs.filenam); /* seed pathname */
if (err=getnams(*v)) prerr(*v, err);
}
}
prlist(ofp, &nlist);
freelist(&nlist);
if (ofp!=stdout) fclose(ofp);
if (IntuitionBase) CloseLibrary(IntuitionBase);
exit(0);
}
/*
If nam is the name of a file, add its size to the global counter.
If nam is the name of a directory, saunter down a level and
grab info for its files.
Return a coded description of any error which occurs, or zero
if success was the order of the day.
*/
getnams(nam)
char *nam;
{
register struct FileLock *l=NULL;
register struct FileInfoBlock *f=NULL;
register err=0;
struct FileLock *Lock();
void addtonam(), truncnam();
if (!nam) return(E_NOEXAM);
if (!(l=Lock(nam, ACCESS_READ))){
return(E_NOLOCK);
}
if (!(f=(struct FileInfoBlock *)AllocMem((ULONG)sizeof(*f), MEMF_PUBLIC))) {
UnLock(l);
return(E_NOMEM);
}
if (!Examine(l, f)) {
UnLock(l);
FreeMem(f, (ULONG)sizeof(*f));
return(E_NOEXAM);
}
if (f->fib_DirEntryType<0){ /* file */
addnam(nam, &nlist);
}
else {
while (ExNext(l, f)){ /* directory */
addtonam(fs.filenam, f->fib_FileName);
if (err=getnams(fs.filenam)) break;
truncnam(fs.filenam); /* delete filename from path */
}
}
UnLock(l);
FreeMem(f, (ULONG)sizeof(*f));
return(err);
}
/*
Assuming p points to a valid pathname and s to a valid filename,
append the filename to the pathname.
*/
void
addtonam(p, s)
register char *p, *s;
{
register char *op=p;
while (*p)
p++;
if (p!=op){
if (*--p!=':')
*++p='/';
p++;
}
while (*s)
*p++=*s++;
*p='\0';
}
/*
Assuming p points to a valid pathname, clip the filename from it.
*/
void
truncnam(p)
register char *p;
{
register char *pp;
if (!p) return;
for (pp=p; *pp; pp++)
;
while (*pp!='/'&&*pp!=':'&&pp>p)
--pp;
if (*pp==':') ++pp;
*pp='\0';
}
/*
Build a real pathname from the filename,
dirname, or drivename specifiecd in nam
into bu. Return a pointer to bu on success,
or NULL if the chore is beyond doing.
*/
char *
realnam(nam, bu)
char *nam, *bu;
{
register addcol;
register struct FileLock *l=NULL;
struct FileLock *Lock();
if (!nam||!bu) return(NULL);
if (nam[strlen(nam)-1]==':') addcol=1;
else addcol=0;
if (!(l=Lock(nam, ACCESS_READ))){
return(NULL);
}
fullnam(l, bu);
UnLock(l);
return(bu);
}
/*
Put the full name of the current
directory into the supplied buffer
and return a pointer to it.
*/
char *
getcd(bu)
char *bu;
{
struct FileLock *ol;
if (!bu) return(NULL);
fullnam(ol=CurrentDir(0L), bu);
CurrentDir(ol);
return(bu);
}
/*
Put the full pathname of a
locked file in the given buffer
and return a pointer to it.
*/
char *
fullnam(l, bu)
register struct FileLock *l;
char *bu;
{
register len;
struct FileLock *nl, *ParentDir();
char bu2[NAMSIZ];
char ebu[NAMSIZ*10];
if (!l||!bu) return(NULL);
bu2[0]=0;
locknam(l, bu);
while (l=ParentDir(l)){
if (locknam(l, bu2)){
sprintf(ebu, "%s/%s", bu2, bu);
strcpy(bu, ebu);
}
else break;
}
if (bu2[0]) bu[strlen(bu2)]=':';
else {bu[len=strlen(bu)]=':'; bu[len+1]='\0';}
return(bu);
}
/*
Put the name of the file or directory
associated with the given lock into
the given buffer and return a pointer
to it or NULL if it couldn't be done.
*/
char *
locknam(l, bu)
register struct FileLock *l;
char *bu;
{
register struct FileInfoBlock *f=NULL;
if (!l||!bu) return(NULL);
if (!(f=(struct FileInfoBlock *)AllocMem((ULONG)sizeof(*f), MEMF_PUBLIC))) {
return(NULL);
}
if (!Examine(l, f)) {
FreeMem(f, (ULONG)sizeof(*f));
return(NULL);
}
strcpy(bu, f->fib_FileName);
FreeMem(f, (ULONG)sizeof(*f));
return(bu);
}
/*
Add a name to the end of the filename list.
Could be more efficient, but the bottleneck
is disk speed. Return a descriptive error
value on failure.
*/
addnam(s, lp)
char *s;
struct namlist *lp;
{
struct namlist *newnode();
char *strsave();
void freelist(), prlist();
if (!s||!lp) return(-1);
if (amtfree()<MEMFLOOR){ /* dump if mem full */
prlist(ofp, lp);
freelist(lp);
}
while (lp->next)
lp=lp->next;
if (!(lp->next=newnode()))
return(E_NONODE); /* won't happen. Better not. */
if (!(lp->next->nam=strsave(s)))
return(E_NOSTRING);
return(0);
}
/*
Allocate a new node for the filename list.
Return a pointer to it or NULL if there's
not enough memory.
*/
struct namlist *
newnode()
{
register struct namlist *mp;
if (mp=(struct namlist *)malloc(sizeof(struct namlist))){
mp->nam=NULL;
mp->next=NULL;
}
return(mp);
}
/*
Free the filename list.
*/
void
freelist(lp)
struct namlist *lp;
{
struct namlist *p;
if (!lp) return;
lp=lp->next; /* don't free 1st item */
while (lp){
p=lp->next;
free(lp->nam);
free(lp);
lp=p;
}
}
/*
Print out the filename list.
*/
void
prlist(fp, lp)
FILE *fp;
struct namlist *lp;
{
if (!lp||!fp) return;
lp=lp->next; /* don't print 1st item */
while (lp){
fprintf(fp, "%s\n", lp->nam);
lp=lp->next;
}
}
/*
An old favorite.
*/
char *
strsave(s)
char *s;
{
register len;
register char *mp;
if (!s) return(NULL);
if (mp=malloc(len=strlen(s)+1))
memcpy(mp, s, len);
return(mp);
}
/*
Report amount of free memory in the system.
Errors not allowed here.
*/
ULONG
amtfree()
{
ULONG c, f;
Forbid();
c=AvailMem(MEMF_CHIP);
f=AvailMem(MEMF_FAST);
Permit();
return(c+f);
}
/*
Print a message corresponding to the error given,
prompting with s, if nonnull.
Return the error given.
*/
prerr(s, err)
char *s;
{
register char *errp;
switch (err){
case E_NOMEM:
errp="Out of memory"; break;
case E_NOEXAM:
errp="Couldn't examine"; break;
case E_NOLOCK:
errp="File not found"; break;
case E_OUTPUT:
errp="Can't open output file"; break;
case E_USAGE:
errp="Usage: qcat [-o outputfile] [-c drivename] or \n\
qcat [-o outputfile] dirname";
break;
case E_LIBRARY:
errp="Couldn't open intuition.library";
break;
default: /* NOTREACHED */
errp="grievous error"; break;
}
if (s) printf("%s: %s\n", s, errp);
else printf("%s\n", errp);
return(err);
}
/*
Set up the AutoRequest stuff, and use the
automatic requestor to tell the user when
to change disks, let them quit, and return
when they do so.
*/
char *rsp_bod0="Insert a disk";
char *rsp_bod1="Next disk";
char *rsp_no="Quit";
char *rsp_yes="Redo";
struct response {
struct IntuiText bod;
struct IntuiText no;
ULONG yflg;
struct Window *w;
} rsp;
/*
Initialize the autorequestor's data and
find a window to put it in. Return nonzero
on failure, zero on success.
*/
getrspinit()
{
rsp.bod.FrontPen=0;
rsp.bod.BackPen=1;
rsp.bod.DrawMode=JAM1;
rsp.bod.LeftEdge=6;
rsp.bod.TopEdge=3;
rsp.bod.ITextFont=NULL;
rsp.bod.IText=rsp_bod0;
rsp.bod.NextText=NULL;
rsp.no=rsp.bod;
rsp.no.IText=rsp_no;
rsp.yflg=DISKINSERTED;
return(!(rsp.w=getCLIwin()));
}
/*
Return a pointer to a window for
the requestor. If there be none,
return NULL.
*/
struct Window *
getCLIwin()
{
register struct Screen *sp;
register struct Window *wp;
return(IntuitionBase->ActiveWindow);
}
/*
Post a requestor asking for a new
disk. The first time called, just
ask for the first disk; after that,
ask for the next. Return the boolean
value of the user's response.
*/
getresponse()
{
register rv=0;
rv=AutoRequest(rsp.w, &rsp.bod, NULL, &rsp.no, rsp.yflg, 0L, 200, 50);
rsp.bod.IText=rsp_bod1;
return(rv);
}